package cn.thornbird.orgsync.config;

import cn.thornbird.orgsync.entity.status.Status;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import reactor.util.annotation.Nullable;

import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Configuration
@Slf4j
public class JsonConfig implements WebMvcConfigurer {

    @Value("${spring.mvc.date-format}")
    private String mvcDateFormat;

    @Value("${spring.mvc.locale}")
    private String mvcLocale;

    @Value("${spring.jackson.date-format}")
    private String jacksonDateFormat;

    @Value("${spring.jackson.time-zone}")
    private String jacksonTimeZone;

    @Bean
    public ObjectMapper jacksonObjectMapperCustomization() {
        SimpleDateFormat format = new SimpleDateFormat(jacksonDateFormat);
        TimeZone timeZone = TimeZone.getTimeZone(jacksonTimeZone);
        format.setTimeZone(timeZone);
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .timeZone(timeZone)
                .dateFormat(format);
        return builder.build();
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DateConverter(mvcDateFormat, mvcLocale));
        registry.addConverterFactory(new ConverterFactory<Object, Status>() {
            @Override
            public <T extends Status> Converter<Object, T> getConverter(Class<T> targetType) {
                T[] enums = targetType.getEnumConstants();
                return source -> {
                    for (T e : enums) {
                        if (e.name().equals(source)) {
                            return e;
                        }
                    }
                    throw new IllegalArgumentException("枚举value不正确");
                };
            }
        });
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(c -> c instanceof MappingJackson2HttpMessageConverter);
        converters.add(new MappingJackson2HttpMessageConverter(jacksonObjectMapperCustomization()));
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
    }


    static class DateConverter implements Converter<String, Date> {

        private final String dateFormat;

        private final String locale;

        DateConverter(String dateFormat, String locale) {
            this.dateFormat = dateFormat;
            this.locale = locale;
        }

        @Override
        public Date convert(@Nullable String text) {
            Date date = null;
            if (!StringUtils.isEmpty(text)) {
                try {
                    date = new SimpleDateFormat(dateFormat, Locale.forLanguageTag(locale)).parse(text.trim());
                } catch (ParseException e) {
                    log.error("error", e);
                }
            }
            return date;
        }

    }

}
